﻿// -----------------------------------------------------------------------
// <copyright file="OdpNetConnectionStringBuilder.cs" company="JSC Centido">
//  Copyright (c) JSC Centido. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

using System.Linq;

namespace Centido.Core
{
    using System;

    /// <summary>
    ///   ODP.NET connection string builder
    /// </summary>
// ReSharper disable InconsistentNaming
    public sealed class OracleConnectionStringBuilder : ConnectionStringBuilder
// ReSharper restore InconsistentNaming
    {
        /// <summary>
        ///   The Oracle ODBC driver name.
        /// </summary>
        public const string DbProviderNameValue = "ORACLE";


        /// <summary>
        ///   Gets the target rdbms product name.
        /// </summary>
        public override string DbProviderName 
        {
            get { return DbProviderNameValue; }
        }


        /// <summary>
        ///   Gets the target rdbms product name.
        /// </summary>
        public override string ProductName
        {
            get { return "ORACLE"; }
        }


        /// <summary>
        ///   Build connection string
        /// </summary>
        /// <returns></returns>
        public override string Build()
        {
            if (PortNumber == 0)
            {
                // Setting default port number
                PortNumber = 1521;
            }

            // If the user has elevated privileges
            if (HasElevatedPrivileges
                // and those privileges were no specified before
                && !UserPassword.ToUpper().Contains("SYSDBA"))
                UserPassword += " AS SYSDBA";

            var connectionString =
                string.Format("Driver={{{0}}};dbq={1}:{2}/{3};Uid={4};Pwd={5};",
                    Driver,
                    Host,
                    PortNumber,
                    DbName,
                    UserName,
                    UserPassword);

            return connectionString;
        }

        /// <summary>
        ///   Parse connection string
        /// </summary>
        /// <param name = "connectionString">Connection string</param>
        public override void Parse(string connectionString)
        {
            if (connectionString == null)
                throw new ArgumentNullException("connectionString");
            if (connectionString.Trim().Length == 0)
                throw new ArgumentException("Connection string cannot be empty.");

            // Parsing the driver name
            Driver = ParseDriverName(connectionString) ?? Driver;

            Host = ParseHost(connectionString) ?? Host;
            PortNumber = ParsePortNumber(connectionString);
            DbName = ParseDbName(connectionString) ?? DbName;

            UserName = ParseStringParameter(connectionString, "Uid") ?? UserName;
            UserPassword = ParseStringParameter(connectionString, "Pwd") ?? UserPassword;
        }
        

        /// <summary>
        ///   Parses the host name from the connection string.
        /// </summary>
        /// <param name = "connectionString">The connection string.</param>
        /// <returns>Returns the host name.</returns>
        private static string ParseHost(string connectionString)
        {
            // Searching for the host name
            var hostStrValue = ParseStringParameter(connectionString, "dbq");

            // Splitting by semicolon
            var parts = hostStrValue.Split(':');

            return parts.FirstOrDefault();
        }


        /// <summary>
        ///   Parses the port number from the the connection string.
        /// </summary>
        /// <param name = "connectionString">The connection string.</param>
        /// <returns>Returns the port number.</returns>
        private static int ParsePortNumber(string connectionString)
        {
            // Searching for the host name
            var hostStrValue = ParseStringParameter(connectionString, "dbq");

            // Splitting by semicolon
            var parts = hostStrValue.Split(':');

            if (parts.Length > 1)
            {
                // Splitting by /
                var subParts = parts[1].Split('/');
                
                if (subParts.Length > 0)
                    return int.Parse(subParts[0]);
            }

            return 1521;
        }


        /// <summary>
        ///   Parses the database name from the connection string.
        /// </summary>
        /// <param name = "connectionString">The connection string.</param>
        /// <returns>Returns the database name.</returns>
        private static string ParseDbName(string connectionString)
        {
            // Searching for the host name
            var hostStrValue = ParseStringParameter(connectionString, "dbq");

            // Splitting by semicolon
            var parts = hostStrValue.Split(':');

            if (parts.Length > 1)
            {
                // Splitting by /
                var subParts = parts[1].Split('/');

                if (subParts.Length > 1)
                    return subParts[1];
            }

            return "XE";
        }


        /// <summary>
        ///   Creates a new connection string builder of the current type.
        /// </summary>
        /// <returns>Returns a new connection string builder that has the same type
        /// as the current one.</returns>
        public override ConnectionStringBuilder CreateNew()
        {
            return new OracleConnectionStringBuilder();
        }
    }
}